//
//  Socket.cpp
//  http_server
//
//  Created by Zirpon Cheung on 15-3-24.
//  Copyright (c) 2015年 Zirpon Cheung. All rights reserved.
//

#include "Socket.h"

Socket::Socket():_host((char*)malloc(sizeof(char) * 100))
{
    _fd     = -1;
    _port   = 0;
    _port   = 0;
}

bool Socket::init(const char *host, unsigned short port, unsigned short back)
{
    if (host != NULL) {
        memcpy(_host, host, strlen(host));
    }
    if (!strlen(_host)) {
        getLocalhost("en0", _host);
    }
    
    _port = port;
    _fd   = create_listener();
    _back = back;
    
    if (_fd == -1) {
        return false;
    }
    return true;
}

int Socket::create_listener()
{
    int _fd = socket(AF_INET, SOCK_STREAM, 0);
    if (_fd == -1)
    {
        syslog(LOG_ERR,"%s", "socket()");
        return _fd;
	}
    
    set_reuse(_fd);
    
    sockaddr_in addr;
    memset(&addr, sizeof(sockaddr_in), 0);
    addr.sin_family        = AF_INET;
    addr.sin_port          = htons(_port);
    addr.sin_addr.s_addr   = INADDR_ANY;
    
    if (!strlen(_host))
    {
        addr.sin_addr.s_addr = inet_addr(_host);
    }
    
    int ret;
    do {
        ret = bind(_fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));

        if (ret < 0) {
            syslog(LOG_INFO,"%s", "bind");
            break;
        }

        ret = listen(_fd, _back);
        if (ret < 0) {
            syslog(LOG_INFO,"%s", "listen");
            break;
        }
    } while (0);

    if (ret < 0) {
        ::close(_fd);
        _fd = -1;
    }
    
    return _fd;
}

int Socket::in_event()
{
    sockaddr addr;
    socklen_t socklen = sizeof(sockaddr);
    int clientfd = accept(_fd, (sockaddr*)&addr, &socklen);
    if (clientfd < 0)
    {
        syslog(LOG_INFO,"%s", "accept");
        return clientfd;
    }
    set_nonblocking(clientfd);
    
//    char ip[64] = "";
//    void* data = NULL;
//    if (addr.sa_family == AF_INET){
//        data = &((sockaddr_in*)&addr)->sin_addr;
//    }
//    else if(addr.sa_family == AF_INET6){
//        data = &((sockaddr_in6*)&addr)->sin6_addr;
//    }
//    if (data){
//        inet_ntop(addr.sa_family, data, ip, socklen);
//    }
    
    char buffer[MAXBUF + 1];
    memset(buffer, '\0', MAXBUF + 1);
    sprintf(buffer, "connect come from: %s:%d\n",
                    inet_ntoa(((sockaddr_in*)&addr)->sin_addr),
                    ntohs(((sockaddr_in*)&addr)->sin_port));
    
    syslog(LOG_INFO,"%s", buffer);

    
    return clientfd;
}

void Socket::close()
{
    ::close(_fd);
}

bool Socket::set_reuse(int fd)
{
    int reuse = 1;
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
    
    return true;
}

bool Socket::set_nonblocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0;
}

bool Socket::getLocalhost(const char *netname, char* result)
{
    int inet_sock;
    struct ifreq ifr;
    inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
    strcpy(ifr.ifr_name, netname);
    if (ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0)
    {
        syslog(LOG_INFO,"%s", "bind");
        return false;
    }
    sprintf(result, "%s",
                inet_ntoa(((sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
    
    return true;
}






















